home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-04-03 | 7.3 KB | 148 lines | [TEXT/pdos] |
- Apple II
- Technical Notes
- _____________________________________________________________________________
- Developer Technical Support
-
- Apple IIGS
- #1: How to Install Custom BRK and /NMI Handlers
-
- Revised by: Jim Mensch & Jim Merritt November 1988
- Written by: Jim Merritt October 1986
-
- This Technical Note discusses a method to install a custom debugger or
- debugging stub within the Apple IIGS system.
- _____________________________________________________________________________
-
-
- Introduction
-
- This Technical Note discusses a particular method that you may use to install
- a custom debugger or debugging stub within the Apple IIGS system. The
- strategy and techniques described here should be of special interest to those
- who wish to operate the Apple IIGS as a slave to a debugger that resides on
- another machine.
-
- Typically, an interrupt handler should pass control to a debugger or debugging
- stub whenever the processor executes a BRK instruction, or when an interface
- card triggers a non-maskable interrupt (/NMI). To simplify the design of the
- debugger, the Apple IIGS Monitor should be responsible for the following:
-
- o saving all machine state information in locations that the
- debugger can access
- o setting the machine to a known state
- o passing control to an arbitrary debugger
- o restoring the remembered machine state upon regaining control from
- the debugger
- o resurrecting the interrupted process
-
- The Monitor is designed to provide all of the services above for the BRK
- instruction, but only the third for /NMI interrupts. In addition, Apple II
- family systems are generally intolerant of /NMI interrupts. In this Technical
- Note we concentrate on the means by which you can install your own custom BRK
- handler, although we also briefly examine /NMI considerations.
-
-
- Dealing With BRK
-
- A BRK interrupt handler may reside at any address in memory. The Monitor
- passes control to your code by executing a JSL instruction; consequently, your
- routine must terminate with an RTL instruction. To install your BRK handler,
- simply load it into memory, call the Miscellaneous Tool Set GetVector routine
- to fetch the address of the current BRK handler, put that address in a safe
- place, then supply the address of your handler to the Miscellaneous Tool Set
- SetVector routine. To deactivate your handler, restore the previous handler
- address using SetVector as follows:
-
- ;
- ; NOTE: All Listings are in APW assembler format.
- ;
-
- INSTMYBRK anop ;Example code to install user's BREAK handler.
- PushLong #0 ;Space for function call result.
- PushWord #$1C ;We want BREAK vector address.
- _GetVector ;Make the call using standard macro.
-
- ; The stack now holds address of the current break handler.
- PLA ;Get and save low word of address...
- STA SBRKADR
- PLA ; ...and now high word.
- STA SBRKADR+2
- PushWord #$1C ;We want to change BREAK vector address.
- PushLong #MYHANDLR ;Address of user's BRK handler.
- _SetVector ;Make the call using standard macro.
-
- ; Custom handler is in place, now go off and do whatever we like...
-
- DEACMYBRK anop ;Example code to deactivate the BRK handler.
- PushWord #$1C ;We want to change BREAK vector address.
- PushLong SBRKADR ;The previous BRK handler address.
- _SetVector ;Make the call using standard macro.
-
- Upon entry to your code, the machine will be in eight-bit native mode.
- Specifically, the m and x bits will be set (forcing eight-bit accumulator,
- memory access, and index registers), the processor will be running at the
- normal (1 MHz) speed, all memory shadowing will be enabled, and both the
- direct page and data bank registers will be reset to zero. The same
- conditions must hold when your BRK handler returns control to the Monitor.
- While your code is active, however, it is free to affect the machine state in
- arbitrary ways, including (but not limited to) widening the registers,
- increasing the clock rate, and disabling shadowing. Before returning control
- to the Monitor, your break handler must also clear the processor's carry flag,
- as an indication that the BRK was indeed serviced by an external handler.
- (Note: The default BREAKVECTOR points to a "no-op" handler that simply sets
- the carry flag to indicate that there is no external handler available, and it
- then executes an RTL.)
-
- When a BRK occurs, the processor saves the machine's state in the BRK.VAR
- area, and you may obtain this address with the Miscellaneous Tool Set GetAddr
- routine as follows:
-
- PushLong #0 ; space for result
- PushWord #9 ; we want BRK.VAR address
- _GetAddr ; make the call using standard macro
-
- ; The stack now holds the address of the BRK.VAR area, expressed as a long
- word (four bytes).
-
-
- Coping With /NMI
-
- Handling /NMI interrupts is, by far, a trickier proposition than fielding BRK
- instructions. For example, the user-definable /NMI jump-vector, /NMI
- ($0003FB), only has room in its three-byte JMP-absolute instruction for a two-
- byte address. Because of this size limitation, at least the "front end" of
- any /NMI handler must reside in bank $00. In addition, the Monitor does not
- "condition" the system in any way before transferring control through the /NMI
- hook, so the system could be in native mode, emulation mode, or any hybrid
- mode (with any screen condition) upon entry to your handler. (Note: Although
- the 65816 processor provides for separate /NMI vector addresses in native and
- emulation modes, the Apple IIGS implementation of these two vectors pass
- control to the same user hook at $0003FB.) The processor only saves minimal
- machine state information when an /NMI occurs; if the handler needs to
- preserve more than the program counter and status register (which are saved
- automatically), then it must do so explicitly. Because the 65816 assumes any
- program running in emulation mode has its program bank register in bank zero,
- it will not save the program bank register for any program running in
- emulation mode outside of bank zero. Code which runs in this manner will
- always crash if it makes any attempt to return from the interrupt. Finally,
- /NMI interrupts can create havoc with disk access and other aspects of the
- system; consequently, the only way you can safely use /NMI interrupts is as a
- one-way "escape hatch" to emergency debugging code.
-
- Here are some ground rules for /NMI interrupt handlers.
-
- o On entry, store any interesting registers or machine state in RAM
- space owned by the handler.
- o Determine whether the processor is in emulation mode or native
- mode.
- o Take appropriate action, depending upon the processor mode.
- o Under no circumstances try to return from the interrupt! Restart
- the system instead.
-
- To install an /NMI handler, load it into some free RAM in bank $00, put the
- two-byte address currently at location /NMI+1 in a safe place, then replace it
- with the address of your handler. To deactivate your handler (assuming
- nothing has yet invoked it), simply restore the previous handler address to
- /NMI+1.
-
-